import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.ArgumentParserException;
import net.sourceforge.argparse4j.inf.Namespace;
import org.xml.sax.SAXException;
import ta.TAGenerator;

import java.util.Optional;

public class Program
{
    public static void main(String[] args)
    {
        ArgumentParser parser = initParser();
        MainConfig config = new MainConfig();
        try
        {
            Namespace res = parser.parseArgs(args);
            config.setInputPath(res.getString("inputPath"));
            config.setOutputPath(res.getString("outputPath"));
            config.setIsDebug(res.getBoolean("isDebug"));
            String fileName = res.getString("fileName");
            String fileNameNoExt = fileName == null ? null : fileName.substring(0, fileName.lastIndexOf('.'));
            config.setFileNameNoExt(fileNameNoExt);
        } catch (ArgumentParserException e)
        {
            e.printStackTrace();
            System.exit(-1);
        }

        MainProcess process = new MainProcess(config);
        process.run();

    }

    private static ArgumentParser initParser()
    {
        ArgumentParser parser = ArgumentParsers.newArgumentParser("BPMN2TA")
                .defaultHelp(true)
                .description("Transform given BPMN2.0 diagram (diagram group) to UPPAAL supported Timed Automate diagram");
        parser.addArgument("-ip", "--input-path")
                .dest("inputPath")
                .type(String.class)
                .nargs("?")
                .required(false)
                .help("Dir path of input .bpmn files.");
        parser.addArgument("-op", "--output-path")
                .dest("outputPath")
                .type(String.class)
                .nargs("?")
                .required(false)
                .help("Dir path of output UPPAAL supported .xml file");
        parser.addArgument("-fn", "--file-name")
                .dest("fileName")
                .type(String.class)
                .nargs("?")
                .required(false)
                .help("File name of output UPPAAL supported .xml file");
        parser.addArgument("-d", "--debug")
                .dest("isDebug")
                .required(false)
                .action(Arguments.storeTrue())
                .help("Enable to show debug info");
        return parser;
    }


}

class MainProcess
{
    private final MainConfig config;
    private final BPMNLoader loader;

    public MainProcess(MainConfig config)
    {
        this.config = config;
        loader = new BPMNLoader(config.getIsDebug(), config.getInputPath(), config.getOutputPath());
    }

    public void run()
    {
        loader.loadBPMNs();
        BPMN2TATransformer transformer = new BPMN2TATransformer(loader.getBpmnContainer().values());
        transformer.transform(config.getFileNameNoExt());
        TAGenerator generator = new TAGenerator(transformer.ta, config.getOutputPath(), config.getFileNameNoExt());
        try
        {
            generator.generate();
        } catch (SAXException e)
        {
            e.printStackTrace();
        }
    }
}

class MainConfig
{
    private final String defaultInputPath = "./bpmnins";
    private final String defaultOutputPath = "./taouts";
    private final String defaultFileNameNoExt = "out";
    private Optional<String> inputPath;
    private Optional<String> outputPath;
    private Optional<String> fileNameNoExt;
    private Optional<Boolean> isDebug;

    public String getInputPath()
    {
        return inputPath.orElse(defaultInputPath);
    }

    public void setInputPath(String inputPath)
    {
        this.inputPath = Optional.ofNullable(inputPath);
    }

    public String getOutputPath()
    {
        return outputPath.orElse(defaultOutputPath);
    }

    public void setOutputPath(String outputPath)
    {
        this.outputPath = Optional.ofNullable(outputPath);
    }

    public String getFileNameNoExt()
    {
        return fileNameNoExt.orElse(defaultFileNameNoExt);
    }

    public void setFileNameNoExt(String fileNameNoExt)
    {
        this.fileNameNoExt = Optional.ofNullable(fileNameNoExt);
    }

    public Boolean getIsDebug()
    {
        return isDebug.orElse(false);
    }

    public void setIsDebug(Boolean isDebug)
    {
        this.isDebug = Optional.ofNullable(isDebug);
    }
}

